#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <newt.h>

#include "newtprog.h"

struct _newtProgressWindow {
    int cur_index;
    int label_num;
    char **label_strs;
    newtComponent *labels;

    int steps;
    newtComponent progress_bar;
};

newtProgressWindow newtProgressWindowOpen(int width, int height, const char *title) {
    newtProgressWindow win;
    int i;

    win = (newtProgressWindow)malloc(sizeof(*win));
    if (!win)
        return win;

    newtCenteredWindow(width, height, title);

    win->label_num = height - 2 /* white */ - 2 /* progress_bar */;
    win->cur_index = 0;

    if (win->label_num <= 0)
        goto err0;

    win->label_strs = (char**)malloc(sizeof(char*) * win->label_num);
    if (win->label_strs == NULL)
        goto err0;

    win->labels = (newtComponent*)malloc(sizeof(newtComponent) * win->label_num);
    if (win->labels == NULL)
        goto err1;

    for (i = 0; i < win->label_num; i++) {
        win->label_strs[i] = NULL;
        win->labels[i] = newtLabel(2, i + 1, "");
    }

    win->progress_bar = newtScale(2, height - 2, width - 4, 100, 0);
    newtScaleSet(win->progress_bar, 0);
    win->steps = 0;

    newtRefresh();

    return win;

  err1:
    free(win->label_strs);
  err0:
    free(win);
    return NULL;
}

void newtProgressWindowPrint0(newtProgressWindow win, int start_newline, const char *fmt, ...) {
    va_list va;
    char buf[1024];
    int i;

    va_start(va, fmt);
    vsnprintf(buf, sizeof(buf), fmt, va);
    va_end(va);

    if (win->cur_index >= win->label_num && start_newline) {
        free(win->label_strs[0]);
        for (i = 0; i < win->label_num - 1; i++) {
            win->label_strs[i] = win->label_strs[i + 1];
            newtLabelSetText(win->labels[i],  win->label_strs[i]);
        }
        win->cur_index = win->label_num - 1;
    }

    if (!start_newline && win->cur_index > 0) {
        win->cur_index--;
        win->label_strs[win->cur_index] = realloc(win->label_strs[win->cur_index],
                                                  strlen(win->label_strs[win->cur_index]) +
                                                  strlen(buf) + 1);
        strcat(win->label_strs[win->cur_index], buf);
    }
    else
        win->label_strs[win->cur_index] = strdup(buf);

    newtLabelSetText(win->labels[win->cur_index], win->label_strs[win->cur_index]);
    win->cur_index++;

    newtRefresh();
}

void newtProgressWindowReport(newtProgressWindow win, int percent) {
    if (percent < 0)
        percent = 0;
    else if (percent > 100)
        percent = 100;

    newtScaleSet(win->progress_bar, percent);
    win->steps = percent;

    newtRefresh();
}

void newtProgressWindowStep(newtProgressWindow win, int steps) {
    if (steps > 0) {
        newtProgressWindowReport(win, win->steps + steps);
    }
}

void newtProgressWindowClose(newtProgressWindow win)
{
    int i;

    for (i = 0; i < win->label_num - 1; i++) {
        free(win->label_strs[i]);
    }
    free(win->label_strs);
    free(win->labels);
    free(win);

    newtPopWindow();
}

#ifdef __NEWTPROG_MAIN__
int main(void) {
    newtProgressWindow win;
    int i;

    newtInit();
    newtCls();

    win = newtProgressWindowOpen(50, 8, "Hardware Initialization");

    newtProgressWindowCont(win, "rock!");
    sleep(1);
    newtProgressWindowCont(win, "rock!");
    sleep(1);
    for (i=1; i <= 10; i++) {
        newtProgressWindowPrint(win, "Do op %d", i);
        newtProgressWindowCont(win, " OK!");
        /* newtProgressWindowReport(win, i*10); */
        newtProgressWindowStep(win, 10);
        sleep(1);
    }
    newtProgressWindowClose(win);

    sleep(2);
    newtFinished();
}
#endif
